/* vcc/hooks.c 
 * 
 * This file is part of vcc. 
 * 
 * vcc is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * vcc is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with vcc. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <locale.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <signal.h>
#include <getopt.h>
#include <libintl.h>
#include <limits.h>

#include <klist.h>
#include <vcc/vcc.h>
#include <vcc/version.h>
#include <vcc/robot.h>
#include <vcc/plugin.h>
#include <vcc/pretty.h>
#include <vcc/hooks.h>
#include <vcc/defserv.h>
#include <vcc/config.h>
#include <vcc/interfaces.h>


struct klist_node hooks = KLIST_NODE_INIT(&hooks);

struct hook *register_hook(int type, hookfn_t hookfn) {
	struct hook *hook;

	if (unlikely(!(hook = malloc(sizeof(struct hook))))) {
		fprintf(stderr, "*** malloc() failed\n");

		return NULL;
	}

	klist_init(&hook->node);
	hook->type = type;
	hook->hook = hookfn;

	klist_add(&hooks, &hook->node);

	return hook;
}


int unregister_hook(struct hook *hook) {
	klist_del(&hooks, &hook->node);
	free(hook);

	return 0;
}


int do_hook(int type, char *s, char *usrname, int sid) {
	struct hook_info 	hi;
	struct klist_node 	*n;
	struct hook 		*hook;
	char 			*p;
	/* times of malloc(). we won't free() when it's 0 */
	int 			i = 0;

	hi.type = type;
	hi.msg = s;
	hi.usr = usrname;
	hi.sid = sid;

	for (n = hooks.next; n != &hooks; n = n->next) {
		hook = hook_of(n);

		if (hook->type == type) {
			p = hook->hook(&hi);

			if (p == HOOK_FAILED) {
				fprintf(stderr, "*** do_hook: one of hooks returned NULL. abandon... \n");
				return 1;
			}

			else if (p == HOOK_HANDLED) {
				*s = 0;

				return 0;
			}

			else if (p == HOOK_IGNORE) 
				continue;

			/* so the order is quiet important */

			if (i) 
				free(hi.msg);

			hi.msg = p;
			i++;
		}
	}

	strcpy(s, hi.msg);

	return 0;
}


int do_hook_recv(char *s, char *usrname, int sid) {
	return do_hook(HOOK_RECV, s, usrname, sid);
}

int do_hook_send(char *s) {
	return do_hook(HOOK_SEND, s, usrname, current_sid);
}


